#ifndef ZL_REGEX_REGEX
#define ZL_REGEX_REGEX

#include "../Basic/Basic.h"
#include "../Basic/String.h"
#include "../Basic/Pointer.h"
#include "../Collections/List.h"
#include "../Collections/Dictionary.h"

namespace zl
{
	namespace regex_internal
	{
		class PureResult;
		class PureInterpretor;
		class RichResult;
		class RichInterpretor;
	};

	template<typename T>
	class IEnumerator : public virtual Interface
	{
	public:
		typedef T									ElementType;

		virtual IEnumerator<T>*						Clone()const = 0;
		virtual const T&							Current()const = 0;
		virtual zint								Index()const = 0;
		virtual bool								Next() = 0;
		virtual void								Reset() = 0;

		virtual bool								Evaluated()const{ return false; }
	};

	template<typename T>
	class IEnumerable : public virtual Interface
	{
	public:
		typedef T									ElementType;

		virtual IEnumerator<T>*						CreateEnumerator()const = 0;
	};

	namespace regex
	{
		class RegexString:public Object
		{
		public:
			std::wstring                              value;
			zint                                      start;
			zint                                      length;
		public:
			RegexString(zint _start=0);
			RegexString(const std::wstring& _string, zint _start, zint _length);
			zint                                       Start()const;
			zint                                       Length()const;
			const std::wstring&                        Value()const;
			bool                                       operator==(const RegexString& string)const;
		};

		class RegexMatch:public Object,public NotCopyable
		{
			friend class Regex;
		public:
			typedef Ptr<RegexMatch>                      Ref;
			typedef collections::List<Ref>               List;
			typedef collections::List<RegexString>       CaptureList;
			typedef collections::Group<std::wstring, RegexString> CaptureGroup;
		protected:
			collections::List<RegexString>                captures;
			collections::Group<std::wstring, RegexString>       groups;
			bool                                          success;
			RegexString                                   result;

			RegexMatch(const std::wstring& _string, regex_internal::PureResult* _result);
			RegexMatch(const std::wstring& _string, regex_internal::RichResult* _result, regex_internal::RichInterpretor* _rich);
			RegexMatch(const RegexString& _string);
		public:
                        bool                                           Success()const;
			const  RegexString&                            Result()const;
			const  CaptureList&                            Captures()const;
			const  CaptureGroup&                           Groups()const;
		};

		class Regex:public Object,private NotCopyable
		{
		protected:
			regex_internal::PureInterpretor*                pure;
			regex_internal::RichInterpretor*                rich;
			void                                            Process(const std::wstring &text, bool keepEmpty,
                                                            bool keepSuccess, bool keepFail, RegexMatch::List& matches)const;
		public:
			Regex(const std::wstring& code, bool preferPure = true);
			~Regex();
			bool                                             IsPureMatch()const;
			bool                                             IsPureTest()const;
			RegexMatch::Ref                                  MatchHead(const std::wstring& text)const;
			RegexMatch::Ref                                  Match(const std::wstring& text)const;
			bool                                             TestHead(const std::wstring& text)const;
			bool                                             Test(const std::wstring& text)const;
			void                                             Search(const std::wstring& text, RegexMatch::List& matches)const;
			void                                             Split(const std::wstring& text,
                                                             bool keepEmptyMatch,RegexMatch::List& matches)const;
			void                                             Cut(const std::wstring& text,
                                                             bool keepEmptyMatch,RegexMatch::List& matches)const;
		};

        class RegexToken
		{
		public:
			zint						start;
			zint						length;
			zint						token;
			const wchar_t*			    reading;
			zint						codeIndex;
			bool						completeToken;
			zint						rowStart;
			zint						columnStart;
			zint						rowEnd;
			zint						columnEnd;
			bool						operator==(const RegexToken& _token)const;
			bool						operator==(const wchar_t* _token)const;
		};

		class RegexTokens : public Object, public IEnumerable<RegexToken>
		{
			friend class RegexLexer;
		protected:
			regex_internal::PureInterpretor*			pure;
			const collections::Array<zint>&				stateTokens;
			std::wstring							    code;
			zint							            codeIndex;
			RegexTokens(regex_internal::PureInterpretor* _pure, const collections::Array<zint>& _stateTokens,
				        const std::wstring& _code, zint _codeIndex);
			RegexTokens(RegexTokens&& rhs);
		public:
		    IEnumerator<RegexToken>*		CreateEnumerator()const;
			collections::List<RegexToken>   ToList();
			void				ReadToEnd(collections::List<RegexToken>& tokens, bool(*discard)(zint) = 0)const;
		};

		class RegexLexerWalker : public Object
		{
			friend class RegexLexer;
		protected:
			regex_internal::PureInterpretor*			pure;
			const collections::Array<zint>&				stateTokens;
			RegexLexerWalker(regex_internal::PureInterpretor* _pure, const collections::Array<zint>& _stateTokens);
		public:
			RegexLexerWalker(const RegexLexerWalker& walker);
			~RegexLexerWalker();
			zint		GetStartState()const;
			zint		GetRelatedToken(zint state)const;
			void		Walk(wchar_t input, zint& state, zint& token, bool& finalState, bool& previousTokenStop)const;
			zint	    Walk(wchar_t input, zint state)const;
			bool		IsClosedToken(const wchar_t* input, zint length)const;
			bool		IsClosedToken(const std::wstring& input)const;
		};

		class RegexLexerColorizer : public Object
		{
			friend class RegexLexer;
		public:
			typedef void(*TokenProc)(void* argument, zint start, zint length, zint token);
		protected:
			RegexLexerWalker	walker;
			zint			currentState;
			RegexLexerColorizer(const RegexLexerWalker& _walker);
		public:
			RegexLexerColorizer(const RegexLexerColorizer& colorizer);
			~RegexLexerColorizer();
			void			Reset(zint state);
			void			Pass(wchar_t input);
			zint			GetStartState()const;
			zint			GetCurrentState()const;
			void			Colorize(const wchar_t* input, zint length, TokenProc tokenProc, void* tokenProcArgument);
		};

		class RegexLexer : public Object, private NotCopyable
		{
		protected:
			regex_internal::PureInterpretor*			pure;
			collections::Array<zint>				ids;
			collections::Array<zint>				stateTokens;
		public:
			//RegexLexer(const IEnumerable<std::wstring>& tokens);
			RegexLexer(const collections::List<std::wstring>& tokens);
			~RegexLexer();
			RegexTokens						Parse(const std::wstring& code, zint codeIndex = -1)const;
			RegexLexerWalker				Walk()const;
			RegexLexerColorizer				Colorize()const;
		};
	};
};
#endif
